﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;

namespace System.ApplicationModel
{
    /// <summary>
    /// Encapsulates a lifetime objects enabled Windows Presentation Foundation (WPF) application.
    /// </summary>
    public abstract class Application : System.Windows.Application
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="Application"/> class.
        /// </summary>
        protected Application() : base() { }
        #endregion

        #region Fields
        private bool _isInitialized;
        private List<IApplicationService> _applicationLifetimeObjects;
        private ReadOnlyCollection<IApplicationService> _applicationLifetimeObjectsWrapper;
        private ApplicationServiceContext _applicationServiceContext;
        #endregion

        #region Properties
        /// <summary>
        /// Gets the application extension services that have been registered for this application.
        /// </summary>
        public IList ApplicationLifetimeObjects
        {
            get
            {
                if (_applicationLifetimeObjects == null)
                {
                    _applicationLifetimeObjects = new List<IApplicationService>();
                }

                if (!this._isInitialized)
                {
                    return _applicationLifetimeObjects;
                }
                else
                {
                    if (_applicationLifetimeObjectsWrapper == null)
                    {
                        _applicationLifetimeObjectsWrapper =
                            new ReadOnlyCollection<IApplicationService>(this._applicationLifetimeObjects);
                    }
                    return _applicationLifetimeObjectsWrapper;
                }
            }
        }

        /// <summary>
        /// Gets the <see cref="System.Windows.Application"/> object for the current <see cref="System.AppDomain"/>.
        /// </summary>
        public static new Application Current
        {
            get { return System.Windows.Application.Current as Application; }
        }
        #endregion

        #region Application Overrides
        /// <summary>
        /// Raises the <see cref="System.Windows.Application.Startup"/> event.
        /// </summary>
        /// <param name="e">A <see cref="System.Windows.StartupEventArgs"/> that contains the event data.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            _applicationServiceContext = new ApplicationServiceContext();   // maybe should parse in the startup args

            foreach (IApplicationService service in this.ApplicationLifetimeObjects)
            {
                service.StartService(_applicationServiceContext);

                IApplicationLifetimeAware ala = service as IApplicationLifetimeAware;
                if (ala != null)
                {
                    ala.Starting();
                }
            }
            this._isInitialized = true;

            base.OnStartup(e);

            foreach (IApplicationService service in this.ApplicationLifetimeObjects)
            {
                IApplicationLifetimeAware ala = service as IApplicationLifetimeAware;
                if (ala != null)
                {
                    ala.Started();
                }
            }
        }

        /// <summary>
        /// Raises the <see cref="System.Windows.Application.Exit"/> event.
        /// </summary>
        /// <param name="e">A <see cref="System.Windows.ExitEventArgs"/> that contains the event data.</param>
        protected override void OnExit(ExitEventArgs e)
        {
            foreach (IApplicationService service in this.ApplicationLifetimeObjects)
            {
                IApplicationLifetimeAware ala = service as IApplicationLifetimeAware;
                if (ala != null)
                {
                    ala.Exiting();
                }
            }

            base.OnExit(e);

            foreach (IApplicationService service in this.ApplicationLifetimeObjects)
            {
                IApplicationLifetimeAware ala = service as IApplicationLifetimeAware;
                if (ala != null)
                {
                    ala.Exited();
                }

                service.StopService();

                IDisposable disposable = service as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }
        }
        #endregion
    }
}
